package main

import (
	"fmt"
	"math"
	"sort"
	"strings"
	"time"
)

// ReplenishmentTaskInfo 单个补水任务的详细信息
type ReplenishmentTaskInfo struct {
	RefillStartTime time.Time // 补水开始时间
	RefillEndTime   time.Time // 补水结束时间
	RefillAmountM3  float64   // 补水量 (m³)
	Reason          string    // 补水原因
	Priority        string    // 优先级 (HIGH/NORMAL/LOW/NONE)
}

// BlockReplenishmentPlan 按3小时区间的补水计划（层级结构）
type BlockReplenishmentPlan struct {
	// 区间信息（固定3小时块）
	BlockStartTime time.Time // 区间开始时间（如 00:00, 03:00, 06:00）
	BlockEndTime   time.Time // 区间结束时间（如 03:00, 06:00, 09:00）
	BlockIndex     int       // 块索引 (0-7)

	// 区间统计信息
	StartLevelM3     float64 // 区间开始时的水位
	EndLevelM3       float64 // 区间结束时的水位
	PredictedUsageM3 float64 // 预测用水量

	// 补水任务列表（该时间块内的所有任务）
	Tasks []*ReplenishmentTaskInfo
}

// ==================== 辅助函数：时间窗口处理 ====================

// findFreeTimeWindows 找出给定时间范围内的空闲窗口
func findFreeTimeWindows(start, end time.Time, occupiedPeriods []TimeRange) []TimeRange {
	if len(occupiedPeriods) == 0 {
		return []TimeRange{{Start: start, End: end}}
	}

	// 合并重叠的占用时段
	mergedOccupied := mergeOverlappingTimeRanges(occupiedPeriods)

	// 按开始时间排序
	sort.Slice(mergedOccupied, func(i, j int) bool {
		return mergedOccupied[i].Start.Before(mergedOccupied[j].Start)
	})

	freeWindows := []TimeRange{}
	currentTime := start

	for _, occupied := range mergedOccupied {
		if occupied.End.Before(start) || occupied.End.Equal(start) {
			continue
		}
		if occupied.Start.After(end) || occupied.Start.Equal(end) {
			break
		}

		occupiedStart := occupied.Start
		occupiedEnd := occupied.End

		if occupiedStart.Before(start) {
			occupiedStart = start
		}
		if occupiedEnd.After(end) {
			occupiedEnd = end
		}

		if currentTime.Before(occupiedStart) {
			if occupiedStart.Sub(currentTime) >= time.Minute {
				freeWindows = append(freeWindows, TimeRange{
					Start: currentTime,
					End:   occupiedStart,
				})
			}
		}

		if occupiedEnd.After(currentTime) {
			currentTime = occupiedEnd
		}
	}

	if currentTime.Before(end) {
		if end.Sub(currentTime) >= time.Minute {
			freeWindows = append(freeWindows, TimeRange{
				Start: currentTime,
				End:   end,
			})
		}
	}

	return freeWindows
}

// mergeOverlappingTimeRanges 合并重叠的时间段
func mergeOverlappingTimeRanges(ranges []TimeRange) []TimeRange {
	if len(ranges) == 0 {
		return []TimeRange{}
	}

	sortedRanges := make([]TimeRange, len(ranges))
	copy(sortedRanges, ranges)

	sort.Slice(sortedRanges, func(i, j int) bool {
		return sortedRanges[i].Start.Before(sortedRanges[j].Start)
	})

	merged := []TimeRange{}
	current := sortedRanges[0]

	for i := 1; i < len(sortedRanges); i++ {
		next := sortedRanges[i]

		if next.Start.Before(current.End) ||
			next.Start.Sub(current.End) <= ConsecutiveGapLimit {
			if next.End.After(current.End) {
				current.End = next.End
			}
		} else {
			merged = append(merged, current)
			current = next
		}
	}

	merged = append(merged, current)
	return merged
}

// ==================== V2完整实现（已修复）====================

// AvailableWindow 表示一个可用的补水窗口
type AvailableWindow struct {
	StartTime     time.Time
	EndTime       time.Time
	MaxCapacityM3 float64
	BlockIndex    int
}

// findAvailableWindows 查找历史块中的可用时间窗口
func (dp *DailyPlanner) findAvailableWindows(block *BlockReplenishmentPlan) []TimeRange {
	blockStart := block.BlockStartTime
	blockEnd := block.BlockEndTime

	occupiedPeriods := []TimeRange{}

	// 1. 已有任务占用的时间
	for _, task := range block.Tasks {
		occupiedPeriods = append(occupiedPeriods, TimeRange{
			Start: task.RefillStartTime,
			End:   task.RefillEndTime,
		})
	}

	// 2. 禁补时段（裁剪到块范围内）
	for _, forbidden := range dp.planner.rules.ForbiddenPeriods {
		if forbidden.End.After(blockStart) && forbidden.Start.Before(blockEnd) {
			start := forbidden.Start
			end := forbidden.End
			if start.Before(blockStart) {
				start = blockStart
			}
			if end.After(blockEnd) {
				end = blockEnd
			}
			occupiedPeriods = append(occupiedPeriods, TimeRange{Start: start, End: end})
		}
	}

	// 3. 找出空闲窗口
	return findFreeTimeWindows(blockStart, blockEnd, occupiedPeriods)
}

// tryMergeWithExistingTask 尝试与已有任务合并
//
// 修复说明：
//  1. 原bug：使用 newStart.Sub(existingTask.RefillEndTime) <= time.Minute
//     当newStart < existingTask.RefillEndTime时，差值为负数，负数永远 <= time.Minute，导致错误合并
//  2. 修复：明确检查时间先后顺序，只在正确的情况下合并
//  3. 新增：检测时间重叠，避免不合理的合并
func (dp *DailyPlanner) tryMergeWithExistingTask(
	block *BlockReplenishmentPlan,
	newStart, newEnd time.Time,
	newAmount float64,
	beneficiaryBlockIndex int,
) bool {
	for _, existingTask := range block.Tasks {

		// ========== 情况1：后置连接 ==========
		// 新任务在已有任务之后：existingTask.End -> newStart -> newEnd
		// 条件：newStart >= existingTask.End 且间隔 <= 1分钟
		if newStart.Equal(existingTask.RefillEndTime) ||
			(newStart.After(existingTask.RefillEndTime) &&
				newStart.Sub(existingTask.RefillEndTime) <= time.Minute) {

			// 安全检查：确保合并后时间顺序正确
			if newEnd.Before(existingTask.RefillStartTime) || newEnd.Equal(existingTask.RefillStartTime) {
				logMessage(LogLevelDebug, "      ├─ ✗ SKIP merge: invalid time order (newEnd=%s <= existingStart=%s)\n",
					newEnd.Format(HourLayout), existingTask.RefillStartTime.Format(HourLayout))
				continue
			}

			// 执行后置合并
			oldEndTime := existingTask.RefillEndTime
			existingTask.RefillEndTime = newEnd
			existingTask.RefillAmountM3 = round2(existingTask.RefillAmountM3 + newAmount)

			// 更新原因描述
			lookbackReason := fmt.Sprintf("Block %d", beneficiaryBlockIndex)
			if existingTask.Reason != "" && !strings.Contains(existingTask.Reason, lookbackReason) {
				existingTask.Reason += fmt.Sprintf(" + Look-back补充（为Block %d服务）", beneficiaryBlockIndex)
			}

			logMessage(LogLevelInfo, "      ├─ ✓ MERGED (extend): [%s-%s→%s] %.2f m³ (added %.2f m³)\n",
				existingTask.RefillStartTime.Format(HourLayout),
				oldEndTime.Format(HourLayout),
				existingTask.RefillEndTime.Format(HourLayout),
				existingTask.RefillAmountM3,
				newAmount)

			return true
		}

		// ========== 情况2：前置连接 ==========
		// 新任务在已有任务之前：newStart -> newEnd -> existingTask.Start
		// 条件：newEnd <= existingTask.Start 且间隔 <= 1分钟
		if newEnd.Equal(existingTask.RefillStartTime) ||
			(newEnd.Before(existingTask.RefillStartTime) &&
				existingTask.RefillStartTime.Sub(newEnd) <= time.Minute) {

			// 安全检查：确保合并后时间顺序正确
			if newStart.After(existingTask.RefillEndTime) || newStart.Equal(existingTask.RefillEndTime) {
				logMessage(LogLevelDebug, "      ├─ ✗ SKIP merge: invalid time order (newStart=%s >= existingEnd=%s)\n",
					newStart.Format(HourLayout), existingTask.RefillEndTime.Format(HourLayout))
				continue
			}

			// 执行前置合并
			oldStartTime := existingTask.RefillStartTime
			existingTask.RefillStartTime = newStart
			existingTask.RefillAmountM3 = round2(existingTask.RefillAmountM3 + newAmount)

			// 更新原因描述
			lookbackReason := fmt.Sprintf("Block %d", beneficiaryBlockIndex)
			if existingTask.Reason != "" && !strings.Contains(existingTask.Reason, lookbackReason) {
				existingTask.Reason += fmt.Sprintf(" + Look-back补充（为Block %d服务）", beneficiaryBlockIndex)
			}

			logMessage(LogLevelInfo, "      ├─ ✓ MERGED (prepend): [%s←%s-%s] %.2f m³ (added %.2f m³)\n",
				newStart.Format(HourLayout),
				oldStartTime.Format(HourLayout),
				existingTask.RefillEndTime.Format(HourLayout),
				existingTask.RefillAmountM3,
				newAmount)

			return true
		}

		// ========== 情况3：时间重叠检测 ==========
		// 如果新任务与已有任务有时间重叠，不应该合并，记录警告
		// 重叠条件：newStart < existingEnd AND newEnd > existingStart
		if newStart.Before(existingTask.RefillEndTime) && newEnd.After(existingTask.RefillStartTime) {
			logMessage(LogLevelDebug, "      ├─ ✗ SKIP merge: time overlap detected\n")
			logMessage(LogLevelDebug, "         New task:      [%s-%s]\n",
				newStart.Format(HourLayout), newEnd.Format(HourLayout))
			logMessage(LogLevelDebug, "         Existing task: [%s-%s]\n",
				existingTask.RefillStartTime.Format(HourLayout), existingTask.RefillEndTime.Format(HourLayout))
			continue
		}
	}

	// 无法与任何已有任务合并
	return false
}

// scheduleSupplementTasks 在可用窗口中安排补充任务（已修复：添加合并逻辑）
func (dp *DailyPlanner) scheduleSupplementTasks(
	block *BlockReplenishmentPlan,
	windows []TimeRange,
	maxCapacity float64,
	deficit *float64,
	beneficiaryBlockIndex int,
) float64 {

	supplemented := 0.0

	for _, window := range windows {
		if *deficit <= MinRefillAmountM3 || supplemented >= maxCapacity {
			break
		}

		duration := window.End.Sub(window.Start).Hours()
		windowCapacity := duration * InflowRateM3PerHour

		actualAmount := math.Min(*deficit, windowCapacity)
		actualAmount = math.Min(actualAmount, maxCapacity-supplemented)

		if actualAmount < MinRefillAmountM3 {
			continue
		}

		actualDuration := divide(actualAmount, InflowRateM3PerHour)
		actualEndTime := window.Start.Add(time.Duration(actualDuration * float64(time.Hour)))

		// ✅ 修复：尝试与已有任务合并
		merged := dp.tryMergeWithExistingTask(
			block,
			window.Start,
			actualEndTime,
			actualAmount,
			beneficiaryBlockIndex,
		)

		if !merged {
			// 如果不能合并，创建新任务
			supplementTask := &ReplenishmentTaskInfo{
				RefillStartTime: window.Start,
				RefillEndTime:   actualEndTime,
				RefillAmountM3:  round2(actualAmount),
				Reason:          fmt.Sprintf("Look-back补充（为Block %d服务）", beneficiaryBlockIndex),
				Priority:        "HIGH",
			}

			block.Tasks = append(block.Tasks, supplementTask)

			logMessage(LogLevelInfo, "      ├─ + NEW task: [%s-%s] %.2f m³ (%.1f min)\n",
				supplementTask.RefillStartTime.Format(HourLayout),
				supplementTask.RefillEndTime.Format(HourLayout),
				supplementTask.RefillAmountM3,
				actualDuration*60)
		}

		supplemented += actualAmount
		*deficit -= actualAmount
	}

	return supplemented
}

// cascadeWaterLevelUpdate 级联更新水位（新增方法）
func (dp *DailyPlanner) cascadeWaterLevelUpdate(
	blockPlans []*BlockReplenishmentPlan,
	fromBlockIndex int,
	toBlockIndex int,
) {
	logMessage(LogLevelDebug, "\n  [CASCADE UPDATE] Updating water levels from Block %d to Block %d...\n",
		fromBlockIndex, toBlockIndex)

	// 从修改的块开始，重新计算后续所有块的水位
	for i := fromBlockIndex; i <= toBlockIndex; i++ {
		block := blockPlans[i]

		// 重新计算该块的总补水量
		totalRefill := 0.0
		for _, task := range block.Tasks {
			totalRefill += task.RefillAmountM3
		}

		// 更新结束水位
		newEndLevel := round2(block.StartLevelM3 - block.PredictedUsageM3 + totalRefill)

		// 物理限制
		if newEndLevel > MaxSafeLevelM3 {
			newEndLevel = MaxSafeLevelM3
		}
		if newEndLevel < 0 {
			newEndLevel = 0
		}

		oldEndLevel := block.EndLevelM3
		block.EndLevelM3 = newEndLevel

		logMessage(LogLevelDebug, "    Block %d: Start=%.2f, Usage=%.2f, Refill=%.2f, End=%.2f→%.2f m³\n",
			i, block.StartLevelM3, block.PredictedUsageM3, totalRefill, oldEndLevel, newEndLevel)

		// 更新下一个块的开始水位
		if i+1 <= toBlockIndex && i+1 < len(blockPlans) {
			blockPlans[i+1].StartLevelM3 = block.EndLevelM3
		}
	}

	logMessage(LogLevelDebug, "  [CASCADE UPDATE] Complete.\n")
}

// lookBackAndSupplementV2 向前回溯，在历史时段补充补水任务（已修复）
func (dp *DailyPlanner) lookBackAndSupplementV2(
	blockPlans []*BlockReplenishmentPlan,
	currentBlockIndex int,
	deficit float64,
) float64 {

	logMessage(LogLevelInfo, "\n[LOOK-BACK V2] Current block needs additional %.2f m³\n", deficit)
	logMessage(LogLevelInfo, "Searching for available capacity in previous blocks...\n")

	originalDeficit := deficit

	for i := currentBlockIndex - 1; i >= 0 && deficit > MinRefillAmountM3; i-- {
		historicalBlock := blockPlans[i]

		logMessage(LogLevelDebug, "\n  Checking Block %d [%s-%s]...\n",
			historicalBlock.BlockIndex,
			historicalBlock.BlockStartTime.Format(HourLayout),
			historicalBlock.BlockEndTime.Format(HourLayout))

		// 1. 找出该块的可用时间窗口
		availableWindows := dp.findAvailableWindows(historicalBlock)

		if len(availableWindows) == 0 {
			logMessage(LogLevelDebug, "    No available windows in this block.\n")
			continue
		}

		logMessage(LogLevelDebug, "    Found %d available window(s):\n", len(availableWindows))
		for idx, w := range availableWindows {
			duration := w.End.Sub(w.Start).Hours()
			capacity := duration * InflowRateM3PerHour
			logMessage(LogLevelDebug, "      Window %d: [%s-%s] (%.1f min, capacity: %.2f m³)\n",
				idx+1, w.Start.Format(HourLayout), w.End.Format(HourLayout),
				duration*60, capacity)
		}

		// 2. 计算该块的剩余容量
		totalRefillInBlock := 0.0
		for _, task := range historicalBlock.Tasks {
			totalRefillInBlock += task.RefillAmountM3
		}

		// 该块的理论最大补水量 = 块时长 * 进水速率
		blockDuration := historicalBlock.BlockEndTime.Sub(historicalBlock.BlockStartTime).Hours()
		theoreticalMaxRefill := blockDuration * InflowRateM3PerHour

		// 剩余容量 = 理论最大 - 已使用
		remainingCapacity := theoreticalMaxRefill - totalRefillInBlock

		// 还需要考虑不能让该块的结束水位超过最大安全水位
		maxAllowableRefill := MaxSafeLevelM3 - (historicalBlock.StartLevelM3 - historicalBlock.PredictedUsageM3 + totalRefillInBlock)

		// 实际可用容量取两者的最小值
		actualCapacity := math.Min(remainingCapacity, maxAllowableRefill)

		if actualCapacity <= MinRefillAmountM3 {
			logMessage(LogLevelDebug, "    Block capacity exhausted (remaining: %.2f m³, max allowable: %.2f m³)\n",
				remainingCapacity, maxAllowableRefill)
			continue
		}

		logMessage(LogLevelDebug, "    Available capacity: %.2f m³ (theoretical: %.2f, max allowable: %.2f)\n",
			actualCapacity, remainingCapacity, maxAllowableRefill)

		// 3. 在可用窗口中安排补充任务
		//beforeDeficit := deficit
		supplemented := dp.scheduleSupplementTasks(
			historicalBlock,
			availableWindows,
			actualCapacity,
			&deficit,
			currentBlockIndex,
		)

		if supplemented > MinRefillAmountM3 {
			logMessage(LogLevelInfo, "    ✓ Block %d contributed: %.2f m³ (remaining deficit: %.2f m³)\n",
				i, supplemented, deficit)

			// ✅ 关键修复：级联更新水位
			dp.cascadeWaterLevelUpdate(blockPlans, i, currentBlockIndex)
		} else {
			logMessage(LogLevelDebug, "    Block %d: No supplementation added\n", i)
		}

		// 如果已经补足，提前退出
		if deficit <= MinRefillAmountM3 {
			break
		}
	}

	totalSupplemented := originalDeficit - deficit

	if totalSupplemented > MinRefillAmountM3 {
		logMessage(LogLevelInfo, "\n[LOOK-BACK V2] ✓ Successfully supplemented %.2f m³ (remaining deficit: %.2f m³)\n",
			totalSupplemented, deficit)
	} else {
		logMessage(LogLevelWarn, "\n[LOOK-BACK V2] ⚠ Could not find sufficient capacity in previous blocks\n")
	}

	return deficit
}

// RunSimulationWithPersistenceV2 运行全天模拟并返回块计划和最终水位（已修复）
func (dp *DailyPlanner) RunSimulationWithPersistenceV2() ([]*BlockReplenishmentPlan, float64) {
	logTitle(LogLevelInfo, fmt.Sprintf("DAILY PLAN SIMULATION V2: %s -> 24:00", dp.startTime.Format(TimeLayout)))

	planningPeriods := calculatePlanningPeriods(dp.startTime, dp.endTime, PlanningHorizon)

	if len(planningPeriods) == 0 {
		logMessage(LogLevelInfo, "No planning periods needed (already at or past 24:00)\n")
		return nil, dp.initialLevel
	}

	logMessage(LogLevelInfo, "Start time: %s\n", dp.startTime.Format(TimeLayout))
	logMessage(LogLevelInfo, "Total planning periods: %d\n", len(planningPeriods))
	logSubTitle(LogLevelInfo)

	var blockPlans []*BlockReplenishmentPlan
	simulatedLevel := dp.initialLevel

	for i, period := range planningPeriods {
		logMessage(LogLevelInfo, "\n=== Processing Period %d: %s -> %s ===\n",
			i+1, period.Start.Format(HourLayout), period.End.Format(HourLayout))

		// 准备调整后的预测数据
		adjustedPrediction3h := make([]float64, len(dp.fullDayPrediction3h)-period.BlockIndex)

		if period.BlockIndex < len(dp.fullDayPrediction3h) {
			copy(adjustedPrediction3h, dp.fullDayPrediction3h[period.BlockIndex:])
			if period.IsPartial && len(adjustedPrediction3h) > 0 {
				originalBlockUsage := dp.fullDayPrediction3h[period.BlockIndex]
				adjustedPrediction3h[0] = multiply(originalBlockUsage, period.UsageFraction)
			}
		} else {
			lastValue := 2.0
			if len(dp.fullDayPrediction3h) > 0 {
				lastValue = dp.fullDayPrediction3h[len(dp.fullDayPrediction3h)-1]
			}
			if period.IsPartial {
				lastValue = multiply(lastValue, period.UsageFraction)
			}
			adjustedPrediction3h = []float64{lastValue, lastValue, lastValue}
		}

		// 构建系统状态
		currentState := SystemState{
			CurrentTime:         period.Start,
			CurrentLevelM3:      simulatedLevel,
			Prediction3h:        adjustedPrediction3h,
			Prediction30min:     dp.fullDayPrediction30min,
			NextDayPrediction3h: dp.nextDayPrediction3h,
			BlockStartTime:      period.BlockStart,
		}

		isLastPeriod := period.BlockIndex == 7

		var tasks []*ReplenishmentTask
		if isLastPeriod {
			tasks = dp.planner.GenerateLastPlan(currentState)
		} else {
			tasks = dp.planner.GeneratePlan(currentState)
		}

		// 计算本周期的实际用水量
		var usageInPeriod float64
		if period.BlockIndex < len(dp.fullDayPrediction3h) {
			baseUsage := dp.fullDayPrediction3h[period.BlockIndex]
			usageInPeriod = multiply(baseUsage, period.UsageFraction)
		} else {
			if len(dp.fullDayPrediction3h) > 0 {
				baseUsage := dp.fullDayPrediction3h[len(dp.fullDayPrediction3h)-1]
				usageInPeriod = multiply(baseUsage, period.UsageFraction)
			} else {
				usageInPeriod = multiply(2.0, period.UsageFraction)
			}
		}

		// 创建BlockPlan
		blockPlan := &BlockReplenishmentPlan{
			BlockStartTime:   period.BlockStart,
			BlockEndTime:     period.End,
			BlockIndex:       period.BlockIndex,
			StartLevelM3:     simulatedLevel,
			PredictedUsageM3: usageInPeriod,
			Tasks:            []*ReplenishmentTaskInfo{},
		}

		refillInPeriod := 0.0
		if len(tasks) > 0 {
			for _, task := range tasks {
				taskInfo := &ReplenishmentTaskInfo{
					RefillStartTime: task.StartTime,
					RefillEndTime:   task.EndTime,
					RefillAmountM3:  task.AmountM3,
					Reason:          task.Reason,
					Priority:        task.Priority,
				}
				blockPlan.Tasks = append(blockPlan.Tasks, taskInfo)
				refillInPeriod += task.AmountM3

				logMessage(LogLevelInfo, "  => Task: [%s] %.2f m³ [%s-%s] (%s)\n",
					task.Priority, task.AmountM3,
					task.StartTime.Format(HourLayout), task.EndTime.Format(HourLayout),
					task.Reason)
			}
		} else {
			logMessage(LogLevelDebug, "  => No task generated\n")
		}

		blockPlans = append(blockPlans, blockPlan)

		// 计算预期的结束水位
		predictedEndLevel := round2(simulatedLevel - usageInPeriod + refillInPeriod)

		// 【关键优化】多种触发条件检查回溯需求
		needsLookBack := false
		deficit := 0.0
		reason := ""

		// 条件1: 结束水位低于最小安全水位
		if predictedEndLevel < MinSafeLevelM3 {
			deficit = MinSafeLevelM3 - predictedEndLevel
			needsLookBack = true
			reason = fmt.Sprintf("ending level (%.2f) < min safe level (%.2f)", predictedEndLevel, MinSafeLevelM3)
		}

		// 执行回溯补充
		if needsLookBack && i > 0 && deficit > MinRefillAmountM3 {
			logMessage(LogLevelWarn, "\n⚠ Look-back triggered: %s (deficit: %.2f m³)\n", reason, deficit)

			remainingDeficit := dp.lookBackAndSupplementV2(blockPlans, period.BlockIndex, deficit)

			if remainingDeficit < deficit {
				// ✅ 成功补充后，当前块的水位已经通过级联更新修正
				// 重新获取更新后的值
				simulatedLevel = blockPlans[period.BlockIndex].StartLevelM3
				predictedEndLevel = blockPlans[period.BlockIndex].EndLevelM3

				// 重新计算补水总量
				refillInPeriod = 0.0
				for _, task := range blockPlans[period.BlockIndex].Tasks {
					refillInPeriod += task.RefillAmountM3
				}

				logMessage(LogLevelInfo, "✓ After look-back: Start=%.2f, End=%.2f m³\n",
					simulatedLevel, predictedEndLevel)
			} else {
				logMessage(LogLevelWarn, "⚠ Look-back could not fully resolve deficit (remaining: %.2f m³)\n",
					remainingDeficit)
			}
		}

		// 更新模拟液位
		nextSimulatedLevel := predictedEndLevel
		if nextSimulatedLevel > MaxSafeLevelM3 {
			nextSimulatedLevel = MaxSafeLevelM3
		}
		if nextSimulatedLevel < 0 {
			nextSimulatedLevel = 0
		}

		blockPlans[len(blockPlans)-1].EndLevelM3 = nextSimulatedLevel

		blockType := "FULL"
		if period.IsPartial {
			blockType = fmt.Sprintf("PARTIAL(%.0f%%)", multiply(period.UsageFraction, 100))
		}

		logMessage(LogLevelInfo, "\nPeriod %d summary [%s -> %s] %s:\n",
			i+1, period.Start.Format(HourLayout), period.End.Format(HourLayout), blockType)
		logMessage(LogLevelInfo, "  Start: %.2f m³, Usage: %.2f m³, Refill: %.2f m³, End: %.2f m³\n",
			simulatedLevel, usageInPeriod, refillInPeriod, nextSimulatedLevel)

		logSubTitle(LogLevelInfo)

		simulatedLevel = nextSimulatedLevel
	}

	logTitle(LogLevelInfo, fmt.Sprintf("SIMULATION COMPLETE - Final Level: %.2f m³", simulatedLevel))

	return blockPlans, simulatedLevel
}

func main() {
	// 设置日志级别
	currentLogLevel = LogLevelInfo

	// 设置用户规则
	today := time.Now()
	loc := today.Location()

	parseTime := func(hourMinute string) time.Time {
		t, _ := time.ParseInLocation(HourLayout, hourMinute, loc)
		return time.Date(today.Year(), today.Month(), today.Day(), t.Hour(), t.Minute(), 0, 0, loc)
	}

	rules := UserRules{
		PriorityPeriods: []TargetedTimeRange{
			{TimeRange: TimeRange{Start: parseTime("03:00"), End: parseTime("06:00")}, TargetLevelM3: 12.0},
			{TimeRange: TimeRange{Start: parseTime("12:00"), End: parseTime("13:00")}, TargetLevelM3: 8.0},
		},
		PeakPeriods: []TargetedTimeRange{
			{TimeRange: TimeRange{Start: parseTime("06:00"), End: parseTime("09:00")}, TargetLevelM3: 12.0},
		},
		ForbiddenPeriods: []TimeRange{
			{Start: parseTime("09:00"), End: parseTime("12:00")},
			{Start: parseTime("13:00"), End: parseTime("18:00")},
		},
	}

	//rules := UserRules{
	//	PriorityPeriods: []TargetedTimeRange{
	//		{TimeRange: TimeRange{Start: parseTime("03:00"), End: parseTime("06:00")}, TargetLevelM3: 12.0},
	//		{TimeRange: TimeRange{Start: parseTime("12:00"), End: parseTime("14:00")}, TargetLevelM3: 10.0},
	//	},
	//	PeakPeriods: []TargetedTimeRange{
	//		{TimeRange: TimeRange{Start: parseTime("06:00"), End: parseTime("09:00")}, TargetLevelM3: 12.0},
	//		{TimeRange: TimeRange{Start: parseTime("18:00"), End: parseTime("24:00")}, TargetLevelM3: 12.0},
	//	},
	//	ForbiddenPeriods: []TimeRange{
	//		{Start: parseTime("09:00"), End: parseTime("12:00")},
	//		{Start: parseTime("14:00"), End: parseTime("16:00")},
	//	},
	//}

	// 准备预测数据
	mockPrediction3h := []float64{2, 4, 8, 6, 4, 4, 6, 4}
	mockPrediction30min := []float64{
		0.2, 0.3, 0.5, 0.5, 0.5, 0.0, // 00:00 - 03:00
		0.2, 0.3, 0.5, 0.5, 0.5, 0.0, // 03:00 - 06:00
		0.5, 0.5, 0.5, 1.0, 1.0, 0.5, // 06:00 - 09:00
		1.5, 1.5, 1.5, 1.5, 1.0, 1.0, // 09:00 - 12:00
	}
	mockNextDayPrediction3h := []float64{2.0, 2.0}

	// 运行模拟
	logMessage(LogLevelInfo, "\n\n")
	logTitle(LogLevelInfo, "测试案例: 从 00:00 开始")
	logMessage(LogLevelInfo, "\n")

	startTime := parseTime("00:00")
	initialLevel := 8.0
	dp := NewDailyPlanner(rules, startTime, initialLevel, mockPrediction3h, mockPrediction30min, mockNextDayPrediction3h)

	// 运行模拟并获取结果
	tasks, finalLevel := dp.RunSimulationWithPersistenceV2()
	print(len(tasks))
	print(finalLevel)
}
